package net.gdface.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.LinkedHashSet;

import static net.gdface.utils.SimpleLog.*;
import static net.gdface.utils.ConditionChecks.checkNotNull;
/**
 * 实现接口<I>实例<T>的代理类 <br>
 * 应用层可以根据需要继承此类重写{@link #invoke(Object, Method, Object[])}方法,
 * 也可以通过注册侦听器{@link InterfaceDecoratorProbe}在方法调用时实现应用逻辑
 * @author guyadong
 *
 * @param <I> 接口类型
 * @param <T> 接口实现类型
 */
public abstract class BaseInterfaceDecorator<I,T> implements InvocationHandler,Delegator<T>,InterfaceDecoratorProbe{
	protected final Class<I> interfaceClass;
	protected final T delegate;
	/** 注册的侦听器列表 */
    private LinkedHashSet<InterfaceDecoratorProbe> listeners = new LinkedHashSet<>();
    /** 是否允许 {@link #beforeInvoke(Object, Method, Object[])}中断调用抛出异常 */
    private final boolean allowBreak;
    private static boolean debug = false;
	public static void setDebug(boolean debug) {
		BaseInterfaceDecorator.debug = debug;
	}
	/**
	 * 构造方法
	 * 
	 * @param interfaceClass 接口类
	 * @param delegate 实现接口的类,如果子类用不delegate字段可以为{@code null}
	 */
	protected BaseInterfaceDecorator(Class<I> interfaceClass, T delegate) {
		this(interfaceClass,delegate,false);
	}
	/**
	 * 构造方法
	 * 
	 * @param interfaceClass 接口类
	 * @param delegate 实现接口的类,如果子类用不delegate字段可以为{@code null}
	 * @param allowBreak 为{@code true}时允许 {@link #beforeInvoke(Object, Method, Object[])}抛出异常
	 */
	protected BaseInterfaceDecorator(Class<I> interfaceClass, T delegate, boolean allowBreak) {
		this.interfaceClass = checkNotNull(interfaceClass, "interfaceClass is null");
		this.delegate = delegate;
		this.allowBreak = allowBreak;
	}
	/**
	 * 简化版构造函数<br>
	 * 当delegate只实现了一个接口时,自动推断接口类型
	 * @param delegate
	 */
	@SuppressWarnings("unchecked")
	protected BaseInterfaceDecorator(T delegate) {
		this((Class<I>) getOnlyInterface(delegate), delegate);
	}
	private static Class<?> getOnlyInterface(Object delegate){
		if(checkNotNull(delegate,"delegate is null").getClass().getInterfaces().length !=1){
			throw new IllegalArgumentException(
				String.format("can't determines interface class from %s", delegate.getClass().getName()));
		}
		return delegate.getClass().getInterfaces()[0];
	}
	protected abstract Object doInvoke(Object proxy, Method method, Object[] args) throws Throwable;
	/**
	 * 执行接口方法调用，在调用前，调用成功后，调用发生异常，调用结束时执行所有注册的侦听器({@link InterfaceDecoratorProbe})
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		try {
			beforeInvoke(proxy, method, args);
			Object result = doInvoke(proxy,method,args);
			onComplete(proxy, method, args, result);
			return result;
		} catch (InvocationTargetException e) {
			Throwable te = e.getTargetException();
			onError(proxy, method, args, te);
			throw te;
		}catch (Throwable e) {
			onError(proxy, method, args, e);
			throw e;
		} finally {
			onDone(proxy, method, args);
		}
	}

	/**
	 * 返回代理的接口类
	 * @return 接口类
	 */
	public final Class<I> getInterfaceClass() {
		return interfaceClass;
	}

	/**
	 * 根据当前对象创建新的接口实例
	 * @return 接口实例
	 * @see Proxy#newProxyInstance(ClassLoader, Class[], InvocationHandler)
	 */
	public final I proxyInstance(){
		return interfaceClass.cast(Proxy.newProxyInstance(
				interfaceClass.getClassLoader(),
				new Class<?>[]{ interfaceClass},
				this));
	}
	@Override
	public T delegate() {
		return delegate;
	}
	/**
	 * 注册侦听器<br>
	 * 重复注册返回{@code false}
	 * @param listener 要注册的侦听器
	 * @return 注册成功返回{@code true},否则返回{@code false}
	 */
	public boolean registerListener(InterfaceDecoratorProbe listener){
		return registerListener(listener,false);
	}
	/**
	 * 注册侦听器<br>
	 * 重复注册返回{@code false}
	 * @param listener 要注册的侦听器
	 * @param header 为{@code true}添加到队列头部,否则顺序添加到尾部
	 * @return 注册成功返回{@code true},否则返回{@code false}
	 */
	public boolean registerListener(InterfaceDecoratorProbe listener, boolean header){
		if(null == listener) {
			return false;
		}
		synchronized (listeners) {
			if(!header) {
				return listeners.add(listener);
			}
			if(!listeners.contains(listener)) {
				/**
				 * 先备份listeners,然后清空之,再将输入listener添加为第一个元素,再将添加备份的内容,
				 * 确保listener为第一个被添加的元素
				 */
				ArrayList<InterfaceDecoratorProbe> copy = new ArrayList<>(listeners);
				listeners.clear();
				listeners.add(listener);
				listeners.addAll(copy);
				return true;
			}
			return false;
		}
	}
	/**
	 * 卸载指定的侦听器
	 * @param listener
	 * @return 卸载成功返回{@code true},否则返回{@code false}
	 */
	public boolean unregisterListener(InterfaceDecoratorProbe listener){
		return listener == null ? false : listeners.remove(listener);
	}
	/**
	 * 顺序调用{@link #listeners}中的所有侦听器对象的
	 * {@link InterfaceDecoratorProbe#beforeInvoke(Object, Method, Object[])}方法,
	 * {@link #allowBreak}为{@code true}时,允许侦听器抛出异常,中断调用,否则输出错误日志
	 */
	@Override
	public void beforeInvoke(Object proxy, Method method, Object[] args) throws Exception {
		for(InterfaceDecoratorProbe listener:listeners){
			try {
				listener.beforeInvoke(proxy, method, args);
			} catch (Exception e) {
				if(allowBreak) {
					throw e;
				}
				log(e.getMessage());
				if(debug){
					log(e.getMessage(),e);
				}
			}
		}		
	}
	/**
	 * 顺序调用{@link #listeners}中的所有侦听器对象的
	 * {@link InterfaceDecoratorProbe#onComplete(Object, Method, Object[], Object)}方法
	 */
	@Override
	public void onComplete(Object proxy, Method method, Object[] args, Object result) {
		for(InterfaceDecoratorProbe listener:listeners){
			try {
				listener.onComplete(proxy, method, args, result);
			} catch (Exception e) {
				log(e.getMessage());
				if(debug){
					log(e.getMessage(),e);
				}
			}
		}
	}
	/**
	 * 顺序调用{@link #listeners}中的所有侦听器对象的
	 * {@link InterfaceDecoratorProbe#onError(Object, Method, Object[], Throwable)}方法
	 */
	@Override
	public void onError(Object proxy, Method method, Object[] args, Throwable error) {
		for(InterfaceDecoratorProbe listener:listeners){
			try {
				listener.onError(proxy, method, args, error);
			} catch (Exception e) {
				log(e.getMessage());
				if(debug){
					log(e.getMessage(),e);
				}
			}
		}		
	}
	/**
	 * 顺序调用{@link #listeners}中的所有侦听器对象的
	 * {@link InterfaceDecoratorProbe#onDone(Object, Method, Object[])}方法
	 */
	@Override
	public void onDone(Object proxy, Method method, Object[] args) {
		for(InterfaceDecoratorProbe listener:listeners){
			try {
				listener.onDone(proxy, method, args);
			} catch (Exception e) {
				log(e.getMessage());
				if(debug){
					log(e.getMessage(),e);
				}
			}
		}
	}
}
